﻿#include "pch.h"
#include "sbcs.h"
#include "PatrickPowell_snprintf.h"

#if _MSC_VER
#pragma warning(push)
#pragma warning(disable:4706)
#endif

//////////////////////////////////////////////////////////////////////////
// 아스키 문자열 처리 

#if SB_BUILD_PRINTF
//
static void _asc_output(kpointer ptr, size_t *currlen, size_t maxlen, int c)
{
	char* buffer = (char*)ptr;
	if (*currlen < maxlen)
		buffer[(*currlen)] = (char)c;
	(*currlen)++;
}

//
static void _asc_output_closure(kpointer ptr, size_t currlen, size_t maxlen)
{
	char* buffer = (char*)ptr;
	if (currlen < maxlen - 1)
		buffer[currlen] = '\0';
	else if (maxlen > 0)
		buffer[maxlen - 1] = '\0';
}

//
static void _asc_file(kpointer ptr, size_t* currlen, size_t maxlen, int c)
{
	FILE* fp = (FILE*)ptr;
	fputc(c, fp);
	(*currlen)++;
}
#endif

/** vsnprintf */
kint k_vsnprintf(char* out, ksize_t len, const char* fmt, va_list va)
{
	ksize_t res;

	k_return_value_if_fail(fmt != NULL, -1);

	res = dopr(_asc_output, _asc_output_closure, out, len, fmt, va);

	if (len)
		len--;

	return out ? (kint)K_MIN(res, len) : (kint)res;
}

/** vaprintf */
kint k_vasprintf(char** out, const char* fmt, va_list va)
{
	ksize_t len;

	k_return_value_if_fail(out != NULL, -2);
	k_return_value_if_fail(fmt != NULL, -1);

	len = dopr(_asc_output, _asc_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
	{
		*out = NULL;
		return 0;
	}

	*out = k_new(len + 1, char);
	len = k_vsnprintf(*out, len + 1, fmt, va);

	return (kint)len;
}

/** vaprintf */
char* k_vapsprintf(const char* fmt, va_list va)
{
	ksize_t len;
	char* ret;

	k_return_value_if_fail(fmt != NULL, NULL);

	len = dopr(_asc_output, _asc_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
		return NULL;

	ret = k_new(len + 1, char);
	k_vsnprintf(ret, len + 1, fmt, va);

	return ret;
}

/** vfprintf */
kint k_vfprintf(FILE* file, const char* fmt, va_list va)
{
	// 16K까지 가능
	k_return_value_if_fail(fmt != NULL, -1);
	return (kint)dopr(_asc_file, NULL, file, 1024 * 16, fmt, va);
}

/** vprintf */
kint k_vprintf(const char* fmt, va_list va)
{
	return k_vfprintf(stdout, fmt, va);
}

/** snprintf */
kint k_snprintf(char* out, ksize_t len, const char* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vsnprintf(out, len, fmt, va);
	va_end(va);

	return ret;
}

/** asprintf */
kint k_asprintf(char** out, const char* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vasprintf(out, fmt, va);
	va_end(va);

	return ret;
}

/** asprintf */
char* k_apsprintf(const char* fmt, ...)
{
	va_list va;
	char* ret;

	va_start(va, fmt);
	ret = k_vapsprintf(fmt, va);
	va_end(va);

	return ret;
}

/** fprintf */
kint k_fprintf(FILE* file, const char* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vfprintf(file, fmt, va);
	va_end(va);

	return ret;
}

/** printf */
kint k_printf(const char* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vprintf(fmt, va);
	va_end(va);

	return ret;
}

/** 문자열 해시 */
ksize_t k_strhash(const char* p)
{
	const char* sz = p;
	ksize_t h = *sz++;
	if (!h)
		return 0;
	else
	{
		kint c;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + *sz;
		h = (h << 5) - h + c;
		return h;
	}
}

/** 문자열 해시 (대소문자구별안함) */
ksize_t k_strihash(const char* p)
{
	const char* sz = p;
	ksize_t h = k_toupper(*sz);
	if (!h)
		return 0;
	else
	{
		kint c;
		sz++;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + k_toupper(*sz);
		h = (h << 5) - h + c;
		return h;
	}
}

/** strlen */
ksize_t k_strlen(const char* p)
{
	const char* o = p;
	while (*p++);
	return p - o - 1;
}

/** strcpy */
char* k_strcpy(char* dest, const char* src)
{
	char* org = dest;
	while ((*dest++ = *src++));
	return org;
}

/** strpcpy */
char* k_strpcpy(char* dest, const char*  src)
{
	do (*dest++ = *src);
	while (*src++ != '\0');
	return dest - 1;
}

/** strncpy */
char* k_strncpy(char* dest, const char* src, ksize_t len)
{
	char* org = dest;

	while (len && (*dest++ = *src++))
		--len;
	*dest = '\0';

	if (len)
	{
		while (--len)
			*dest++ = '\0';
	}

	return org;
}

/** strcat */
char* k_strcat(char* dest, const char* src)
{
	char* org = dest;
	while (*dest) ++dest;
	while ((*dest++ = *src++));
	return org;
}

/** strncat */
char* k_strncat(char* dest, ksize_t len, const char* src)
{
	char* org = dest;

	while (*dest++);
	--dest;

	while (len--)
	{
		if (!(*dest++ = *src++))
			return org;
	}

	*dest = '\0';
	return org;
}

/** strcat의 여러 문자열 버전 */
char* k_strconcat(char* dest, ...)
{
	va_list va;
	char* c = dest;
	char* s;

	while (*c++);
	--c;

	va_start(va, dest);
	s = va_arg(va, char*);
	while (s)
	{
		c = k_strpcpy(c, s);
		s = va_arg(va, char*);
	}
	va_end(va);

	return dest;
}

/** strdup, 복사한 메모리는 k_free 함수로 제거해야 한다 */
char* k_strdup(const char* p)
{
	if (!p)
		return NULL;
	else
	{
		ksize_t len = k_strlen(p) + 1;
		char* d = k_new(len, char);

		k_strcpy(d, p);

		return d;
	}
}

/** strdup에 길이를 설정 */
char* k_strndup(const char* p, ksize_t len)
{
	char* d;
	d = k_new(len + 1, char);
	k_strncpy(d, p, len);
	return d;
}

/** 여러 문자열의 strdup */
char* k_strdupcat(const char* p, ...)
{
	va_list va;
	char* str;
	char* s, *c;
	ksize_t size;

	size = k_strlen(p) + 1;
	va_start(va, p);
	s = va_arg(va, char*);
	while (s)
	{
		size += k_strlen(s);
		s = va_arg(va, char*);
	}
	va_end(va);

	str = k_new(size, char);
	c = str;

	c = k_strpcpy(c, p);
	va_start(va, p);
	s = va_arg(va, char*);
	while (s)
	{
		c = k_strpcpy(c, s);
		s = va_arg(va, char*);
	}
	va_end(va);

	return str;
}

/** strdup에 문자열을 찾아 그 위치를 반환함(fnd 인수) */
char* k_strdupchr(const char* p, const char** fnd, kint ch)
{
	if (!fnd)
		return k_strdup(p);

	if (!p)
		return NULL;
	{
		ksize_t len = k_strlen(p);
		char* d = k_new(len + 1, char);
		char* u;

		// dup
		k_strcpy(d, p);

		// chr
		u = d;
		while (*u && *u != (char)ch) u++;
		*fnd = (*u == (char)ch) ? u : NULL;

		return d;
	}
}

/** strdup에 문자열을 뒤에서 찾아 그 위치를 반환함(fnd 인수) */
char* k_strduprchr(const char* p, const char** fnd, kint ch)
{
	if (!fnd)
		return k_strdup(p);

	if (!p)
		return NULL;
	{
		ksize_t len = k_strlen(p);
		char* d = k_new(len + 1, char);
		char* u;

		// dup
		k_strcpy(d, p);

		// rchr
		u = d + len;
		while (--u != d && *u != (char)ch);
		*fnd = (*u == (char)ch) ? u : NULL;

		return d;
	}
}

/** strrev */
char* k_strrev(char* p)
{
	char* s = p;
	char* l = p;
	char ch;

	while (*s++);
	s -= 2;

	while (l < s)
	{
		ch = *l;
		*l++ = *s;
		*s-- = ch;
	}

	return p;
}

/** strupr */
char* k_strupr(char* p)
{
	char* s = p;

	for (; *s; ++s)
	{
		if ((*s >= 'a') && (*s <= 'z'))
			*s -= 'a' - 'A';
	}

	return p;
}

/** strlwr */
char* k_strlwr(char* p)
{
	char* s = p;

	for (; *s; ++s)
	{
		if ((*s >= 'A') && (*s <= 'Z'))
			*s += 'a' - 'A';
	}

	return p;
}

/** strchr */
char* k_strchr(const char* p, kint ch)
{
	while (*p && *p != (char)ch) p++;
	return (*p == (char)ch) ? (char*)p : NULL;
}

/** strrchr */
char* k_strrchr(const char* p, kint ch)
{
	char* s = (char*)p;
	while (*s++);
	while (--s != p && *s != (char)ch);
	return (*s == (char)ch) ? (char*)s : NULL;
}

/** strstr */
char* k_strstr(const char* p, const char* s)
{
	char* cp = (char*)p;
	char* s1, *s2;

	if (!*s)
		return (char*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (char*)s;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

/** stristr */
char* k_stristr(const char* p, const char* s)
{
	char* cp = (char*)p;
	char* s1, *s2;

	if (!*s)
		return (char*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (char*)s;

		while (*s1 && *s2 && !(k_toupper(*s1) - k_toupper(*s2)))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

/** strrstr */
char* k_strrstr(const char* p, const char* s)
{
	char* cp;
	ksize_t pl, sl, i;

	if (!*s)
		return (char*)p;

	pl = k_strlen(p);
	sl = k_strlen(s);

	if (pl < sl)
		return NULL;

	cp = (char*)p + pl - sl;
	while (cp >= p)
	{
		for (i = 0; i < sl; i++)
		{
			if (cp[i] != s[i])
				goto pos_next;
		}

		return cp;

pos_next:
		p--;
	}

	return NULL;
}

/** strbrk */
char* k_strbrk(const char* p, const char* c)
{
#if 1
	// microsoft c library 13.10
	const char* str = p;
	const char* ctn = c;
	char map[32] = {0, };

	while (*ctn)
	{
		map[*ctn >> 3] |= (1 << (*ctn & 7));
		ctn++;
	}

	while (*str)
	{
		if (map[*str >> 3] & (1 << (*str & 7)))
			return ((char*)str);
		str++;
	}

	return NULL;
#else
	char* t;
	while (*p)
	{
		for (t=(char*)c; *t; t++)
		{
			if (*t==*p)
				return (char*)p;
		}
		p++;
	}
	return NULL;
#endif
}

/** strleft */
char* k_strlft(char* dest, const char* src, ksize_t len)
{
	ksize_t size = k_strlen(src);

	if (len > size)
		k_strcpy(dest, src);
	else
	{
		k_strncpy(dest, src, len);
		*(dest + len) = '\0';
	}

	return dest;
}

/** strright */
char* k_strrgt(char* dest, const char* src, ksize_t len)
{
	ksize_t size = k_strlen(src);

	if (len > size)
		k_strcpy(dest, src);
	else
	{
		k_strncpy(dest, src + size - len, len);
		*(dest + len) = '\0';
	}

	return dest;
}

/** strmid */
char* k_strmid(char* dest, const char* src, ksize_t pos, ksize_t len)
{
	ksize_t size = k_strlen(src);

	if (pos > size)
		*dest = '\0';
	else
	{
		k_strncpy(dest, src + pos, len);
		*(dest + len) = '\0';
	}

	return dest;
}

/** strltrim */
char* k_strltrim(char* dest)
{
	char* s;
	for (s = dest; *s && k_isspace((unsigned char)*s); s++);
	if (dest != s)
		memmove(dest, s, k_strlen(s) + 1);
	return dest;
}

/** strrtrim */
char* k_strrtrim(char* dest)
{
	ksize_t len = k_strlen(dest);
	while (len--)
	{
		if (!k_isspace((unsigned char)dest[len]))
			break;
		dest[len] = '\0';
	}
	return dest;
}

/** strtrim */
char* k_strtrim(char* dest)
{
	return k_strrtrim(k_strltrim(dest));
}

/** strrem */
char* k_strrem(char* p, const char* rmlist)
{
	char* p1 = p;
	char* p2 = p;

	while (*p1)
	{
		const char* ps = (const char*)rmlist;
		kcham b = FALSE;

		while (*ps)
		{
			if (*p1 == *ps)
			{
				b = TRUE;
				break;
			}
			++ps;
		}

		if (!b)
		{
			*p2 = *p1;
			++p2;
		}

		++p1;
	}

	*p2 = '\0';

	return p;
}

/** streqv */
kcham k_streqv(const char* p1, const char* p2)
{
	return (p1 == p2) ? TRUE : k_strcmp(p1, p2) == 0;
}

/** strieqv */
kcham k_strieqv(const char* p1, const char* p2)
{
	return (p1 == p2) ? TRUE : k_stricmp(p1, p2) == 0;
}

/** strcmp */
kint k_strcmp(const char* p1, const char* p2)
{
	kint ret = 0;

	while (!(ret = *p1 - *p2) && *p2)
		++p1, ++p2;

	if (ret < 0)		ret = -1;
	else if (ret > 0)	ret = 1;

	return ret;
}

/** strncmp */
kint k_strncmp(const char* p1, const char* p2, ksize_t len)
{
	if (!len)
		return 0;

	while (--len && *p1 && *p1 == *p2)
		++p1, ++p2;

	return *p1 - *p2;
}

/** stricmp */
kint k_stricmp(const char* p1, const char* p2)
{
	kint	f, l;

	do
	{
		f = (unsigned char)(*(p1++));
		l = (unsigned char)(*(p2++));
		if (f >= 'A' && f <= 'Z')	f -= 'A' - 'a';
		if (l >= 'A' && l <= 'Z')	l -= 'A' - 'a';
	} while (f && (f == l));

	return (f - l);
}

/** strnicmp */
kint k_strnicmp(const char* p1, const char* p2, ksize_t len)
{
	kint	f, l;

	while (len && *p1 && *p2)
	{
		--len;

		f = (unsigned char)(*p1);
		l = (unsigned char)(*p2);
		if (f >= 'A' && f <= 'Z')	f -= 'A' - 'a';
		if (l >= 'A' && l <= 'Z')	l -= 'A' - 'a';

		if (f != l) return (f - l);
		++p1;
		++p2;
	}

	return (len) ? (kint)(p1 - p2) : 0;
}

/**
 * 문자열에서 와일드 카드 찾기.
 * Written by Jack Handy - jakkhandy@hotmail.com
 * (http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing)
 */
kint k_strwcmatch(const char* wild, const char* string)
{
	const char *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != '*'))
	{
		if ((*wild != *string) && (*wild != '?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == '*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((*wild == *string) || (*wild == '?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == '*')
		wild++;

	return !*wild;
}

/**
 * 문자열에서 와일드 카드 찾기.
 * Written by Jack Handy - jakkhandy@hotmail.com
 * (http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing)
 */
kint k_striwcmatch(const char* wild, const char* string)
{
	const char *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != '*'))
	{
		if ((k_toupper(*wild) != k_toupper(*string)) && (*wild != '?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == '*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((k_toupper(*wild) == k_toupper(*string)) || (*wild == '?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == '*')
		wild++;

	return !*wild;
}

/** strfind */
kint k_strfnd(const char* src, const char* find, ksize_t index)
{
	const char* p = src + index;
	const char* s1, *s2;

	while (*p)
	{
		s1 = p;
		s2 = find;

		while (*s1 && *s2 && !(*s1 - *s2))
		{
			++s1;
			++s2;
		}

		if (!*s2)
			return (kint)(src + index - p);
	}

	return -1;
}

/** src에 해당하는 문자열을 찾아 그 순번을 알려준다. 마지막 인수는 널값이어야 한다. */
kint k_streqlv(const char* src, ...)
{
	va_list va;
	const char* s;
	kint n = 1;

	va_start(va, src);
	s = va_arg(va, const char*);

	while (s)
	{
		if (k_streqv(src, s))
			return n;

		s = va_arg(va, const char*);
		n++;
	}

	va_end(va);

	return 0;
}

/** src에 해당하는 문자열을 찾아 그 순번을 알려준다. 마지막 인수는 널값이어야 한다. */
kint k_strieqlv(const char* src, ...)
{
	va_list va;
	const char* s;
	kint n = 1;

	va_start(va, src);
	s = va_arg(va, const char*);

	while (s)
	{
		if (k_strieqv(src, s))
			return n;

		s = va_arg(va, const char*);
		n++;
	}

	va_end(va);

	return 0;
}

/** 문자열이 숫자로 구성되어 있는지 알려준다. 1=숫자, -1=실수, 0=숫자아님 */
kint k_strisnum(const char* s)
{
	kint ret = 1;
	kint dot = 0;
	for (; *s; ++s)
	{
		if (*s == '+' || *s == '-')
			continue;
		else if (!k_isdigit(*s))
		{
			if (*s != '.')
			{
				ret = 0;		// 숫자아님
				break;
			}
			else
			{
				if (dot > 0)
				{
					ret = 0;	// 숫자 아님
					break;
				}
				else
				{
					ret = -1;	// 실수
					++dot;
				}
			}
		}
	}
	return ret;
}

/** strtoi */
kint k_strtoi(const char* p)
{
	kint	value;
	kint ch;
	kint sign;

	while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == '-' || ch == '+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= '0' && ch <= '9') ? ch - '0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == '-') ? -value : value;
}

/** strtol */
klong k_strtol(const char* p)
{
	klong value;
	kint ch;
	kint sign;

	while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == '-' || ch == '+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= '0' && ch <= '9') ? ch - '0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == '-') ? -value : value;
}

/** strtof */
float k_strtof(const char* p, char** sret)
{
	return (float)k_strtod(p, sret);
}

/** strtod */
double k_strtod(const char* p, char** sret)
{
	// code from DJGPP, Copyright (C) 1996 DJ Delorie <http://www.delorie.com/djgpp/>
	double r = 0.0;	// result
	double d;		// scale
	kint e = 0;		// exponent
	kint sign = 1;	// +- 1.0
	kint esign = 1;
	kint i;
	kint flags = 0;

	while ((*p == ' ') || (*p == '\t'))
		++p;

	if (*p == '+')
		++p;
	else if (*p == '-')
	{
		sign = -1;
		++p;
	}

	while ((*p >= '0') && (*p <= '9'))
	{
		flags |= 1;
		r *= 10.0;
		r += *p - '0';
		++p;
	}

	if (*p == '.')
	{
		d = 0.1L;
		++p;
		while ((*p >= '0') && (*p <= '9'))
		{
			flags |= 2;
			r += d*(*p - '0');
			++p;
			d *= 0.1L;
		}
	}

	if (flags == 0)
	{
		if (sret) *sret = (char*)p;
		return 0;
	}

	if ((*p == 'e') || (*p == 'E'))
	{
		++p;
		if (*p == '+')
			++p;
		else if (*p == '-')
		{
			++p;
			esign = -1;
		}
		if ((*p<'0') || (*p>'9'))
		{
			if (sret) *sret = (char*)p;
			return r;
		}

		while ((*p >= '0') && (*p <= '9'))
		{
			e *= 10;
			e += *p - '0';
			++p;
		}
	}

	if (esign < 0)
		for (i = 1; i <= e; ++i)
			r *= 0.1L;
	else
		for (i = 1; i <= e; ++i)
			r *= 10.0;

	if (sret) *sret = (char*)p;

	return r*sign;
}

/** 진수 처리가 가능한 strtoi */
kuint k_strtoi_base(const char* p, kint base)
{
	kuint v;
	kint ch;

	if (!p)
		return 0;

	if (base < 2 || base>32)
		return 0;

	v = 0;
	while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
		++p;

	ch = k_getbtv(*p++);
	while (ch < base)
	{
		v = v*base + ch;
		ch = k_getbtv(*p++);
	}

	return v;
}

/** 진수 처리가 가능한 strtol */
kulong k_strtol_base(const char* p, kint base)
{
	kulong v;
	kint ch;

	if (!p)
		return 0;

	if (base < 2 || base>32)
		return 0;

	v = 0;
	while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
		++p;

	ch = k_getbtv(*p++);
	while (ch < base)
	{
		v = v*base + ch;
		ch = k_getbtv(*p++);
	}

	return v;
}

/** 다음 문자열을 불린 참으로 함 TRUE, YES, CHAM, ON, 1 */
kcham k_strtob(const char* p)
{
	return !p ? FALSE : k_strieqv(p, "1") || k_strieqv(p, "TRUE") || k_strieqv(p, "YES") || k_strieqv(p, "CHAM") || k_strieqv(p, "ON");
}

/** splitpath */
kcham k_splitpath(const char* path, char* drv, kint drv_len, char* dir, kint dir_len, char* filename, kint filename_len, char* ext, kint ext_len)
{
	const char* tmp;
	const char* slash;
	const char* dot;
	kcham drvset = FALSE;
	kint	len = 0;
	kint	n;

	if (drv && drv_len)
		drvset = TRUE;

	if (drvset)
	{
		n = 3 - 2;
		tmp = path;

		while (n > 0 && *tmp != 0)
		{
			--n;
			++tmp;
		}
		if (*tmp == ':')
		{
			k_strncpy(drv, path, 3 - 1);
			path = tmp + 1;
		}
		else
		{
			if (drv)
				*((char*)drv) = '\0';
		}
	}

	slash = NULL;
	dot = NULL;
	tmp = path;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == '/' || *tmp == '\\')
			slash = tmp + 1;
		else if (*tmp == '.')
			dot = tmp;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (char*)path);
			k_strncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((char*)dir) = '\0';
	}

	if (dot && (dot >= (char*)path))
	{
		if (filename && filename_len)
		{
			len = (kint)(dot - (char*)path);
			k_strncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext && ext_len)
		{
			len = (kint)(tmp - dot);
			k_strncpy(ext, dot, (ext_len > len) ? len : ext_len);
		}
	}
	else
	{
		if (filename && filename_len)
		{
			len = (kint)(tmp - (char*)path);
			k_strncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext)
			*((char*)ext) = '\0';
	}

	return TRUE;
}

/** divpath */
kcham k_divpath(const char* path, char* dir, kint dir_len, char* filename, kint filename_len)
{
	const char* slash = NULL;
	const char* tmp = path;
	kint	len;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == '/' || *tmp == '\\')
			slash = tmp + 1;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (const char*)path);
			k_strncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((char*)dir) = '\0';
	}

	if (filename && filename_len)
	{
		len = (kint)(tmp - (const char*)path);
		k_strncpy(filename, path, (filename_len > len) ? len : filename_len);
	}

	return TRUE;
}

/** 스크립트 따옴표 분석 */
char* k_strdquote(char* p, kint quote)
{
	char* c = p;
	char* r = p;
	char buf[4];
	kint i;

	while (*c)
	{
		if (c[0] == quote)
		{
			++c;
			continue;
		}
		else if (c[0] == '\\')
		{
			switch (c[1])
			{
				case '0': case '1': case '2': case '3': case '4':
				case '5': case '6': case '7': case '8': case '9':
					i = 0;
					while (i < 3 && k_isdigit((unsigned char)c[i + 1]))
					{
						buf[i] = c[i + 1];
						++i;
					}
					buf[i] = '\0';
					*r = (char)(k_atoi(buf) & 0xFF);
					c += (i - 1);
					break;

				case 'a': *r = '\a'; break;
				case 'b': *r = '\b'; break;
				case 'f': *r = '\f'; break;
				case 'n': *r = '\n'; break;
				case 'r': *r = '\r'; break;
				case 't': *r = '\t'; break;
				case 'v': *r = '\v'; break;
				case '`': *r = '`'; break;
				case '\'': *r = '\''; break;
				case '\"': *r = '\"'; break;
				case '\\': *r = '\\'; break;
				default: *r = c[1];
			}

			++r;
			c += 2;
			continue;
		}
		*(r++) = *(c++);
	}

	*r = '\0';

	return p;
}

/** 스크립트 따옴표 분석 */
char* k_strsquote(char* p, kint quote)
{
	char* c = p;
	char* r = p;

	while (*c)
	{
		if (c[0] == quote && c[1] == quote && c[2])
		{
			*(r++) = *c;
			c += 2;
			continue;
		}
		else if (c[0] == quote)
		{
			++c;
			continue;
		}

		*(r++) = *(c++);
	}

	*r = '\0';

	return p;
}

/** 빈칸으로 채우기 */
ksize_t k_strspc(char* dest, ksize_t pos, ksize_t end)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = ' ';
	return pos + cnt;
}

/** 글자로 채우기 */
ksize_t k_strfll(char* dest, ksize_t pos, ksize_t end, int ch)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = (char)ch;
	return pos + cnt;
}

/** 한줄 씩 읽기 */
ksize_t k_strlin(const char* text, char* line, ksize_t * readsize, kcham removespace)
{
	const char* pos;
	char* dst;
	ksize_t len;

	if (!text)
		return 0;

	pos = text;
	dst = line;
	for (len = 0;; ++dst, ++pos, ++len)
	{
		if (*pos == '\n' || *pos == '\0')
		{
			++pos;
			++len;
			break;
		}
		*dst = *pos;
	}
	*dst = '\0';

	if (readsize)
		*readsize = len;

	pos = line;
	len = 0;
	if (removespace)
	{
		for (; *pos; ++pos)
		{
			if (*pos == '\n' || *pos == '\r' || *pos == ' ' || *pos == '\t')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	else
	{
		for (; *pos; ++pos)
		{
			if (*pos == '\n' || *pos == '\r')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	*line = '\0';

	return len;
}

/** strtok */
char* k_strtok(char* string, const char* control, char** context)
{
	char* token;
	const char* ctl;

	k_return_value_if_fail(context != NULL, NULL);
	k_return_value_if_fail(string != NULL || *context != NULL, NULL);
	k_return_value_if_fail(control != NULL, NULL);

	if (!string)
		string = *context;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (!*ctl)
			break;
		string++;
	}

	token = string;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (*ctl)
		{
			*string++ = '\0';
			break;
		}
		string++;
	}

	*context = string;

	return token == string ? NULL : token;
}

/* -*- mode: c; c-file-style: "k&r" -*-

  strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
  Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
  claim that you wrote the original software. If you use this software
  in a product, an acknowledgment in the product documentation would be
  appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
  misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
  */

static kint _k_str_nat_cmp_right(char const* a, char const* b)
{
	kint bias = 0;

	for (;; a++, b++)
	{
		if (!k_isdigit(*a) && !k_isdigit(*b))
			return bias;
		else if (!k_isdigit(*a))
			return -1;
		else if (!k_isdigit(*b))
			return +1;
		else if (*a < *b)
		{
			if (!bias)
				bias = -1;
		}
		else if (*a > *b)
		{
			if (!bias)
				bias = +1;
		}
		else if (!*a && !*b)
			return bias;
	}

	//return 0;
}

static kint _k_str_nat_cmp_left(char const* a, char const* b)
{
	for (;; a++, b++)
	{
		if (!k_isdigit(*a) && !k_isdigit(*b))
			return 0;
		else if (!k_isdigit(*a))
			return -1;
		else if (!k_isdigit(*b))
			return +1;
		else if (*a < *b)
			return -1;
		else if (*a > *b)
			return +1;
	}

	//return 0;
}

static kint _k_str_nat_internal(char const* a, char const* b, kcham incase)
{
	char ca, cb;
	kint ai, bi;
	kint frac, res;

	for (ai = bi = 0;;)
	{
		ca = a[ai];
		cb = b[bi];

		while (k_isspace(ca))
			ca = a[++ai];

		while (k_isspace(cb))
			cb = b[++bi];

		if (k_isdigit(ca) && k_isdigit(cb))
		{
			frac = (ca == '0' || cb == '0');

			if (frac)
			{
				res = _k_str_nat_cmp_left(a + ai, b + bi);
				if (res != 0)
					return res;
			}
			else
			{
				res = _k_str_nat_cmp_right(a + ai, b + bi);
				if (res != 0)
					return res;
			}
		}

		if (!ca && !cb)
			return 0;

		if (incase)
		{
			ca = (char)k_toupper(ca);
			cb = (char)k_toupper(cb);
		}

		if (ca < cb)
			return -1;
		else if (ca > cb)
			return +1;

		++ai;
		++bi;
	}
}

/**
 * strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
 * Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
 */
kint k_strnatcmp(const char* left, const char* right)
{
	return _k_str_nat_internal(left, right, FALSE);
}

/**
* strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
* Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
*/
kint k_strnatcasecmp(const char* left, const char* right)
{
	return _k_str_nat_internal(left, right, TRUE);
}

/** 대문자 여부 검사 */
kint k_strisupr(const char* s)
{
	const char* p = s;

	while (*p)
	{
		if (k_isupper(*p))
			return (kint)(p - s);
		p++;
	}

	return -1;
}

/** 소문자 여부 검사 */
kint k_strislwr(const char* s)
{
	const char* p = s;

	while (*p)
	{
		if (k_islower(*p))
			return (kint)(p - s);
		p++;
	}

	return -1;
}

#if _MSC_VER
#pragma warning(pop)
#endif
